/*
 * AXP17x.c
 *
 *  Created on: 2016-6-23
 *      Author: NKJ
 */
#include <stdint.h>
#include <stddef.h>
#include "axp17x.h"



//以下变量需要保存到非易失存储器  用后保存 用前要读取
Batinfo batinfo = {
					0,  	//是否在充电
					0,		//中断状态
					BATRDC, //电池内阻
					0,		//充电库伦计值
					BATCAP, //电池满充容量
					BATCAP,	//电池开始放电或结束充电时的电量     	 mAh
					BATCAP,	//电池剩余可用容量
					100,	//电量百分比
					4200,	//电压
					100,	//电流
					250,	//温度
					0,		//放电时间
					0,		//充电时间
					0		//充放电次数
					};



uint8_t AXP17x_swandvoltctrl(uint8_t ctrlreg,uint8_t voltreg,uint8_t swbit,uint8_t sw,uint16_t volt,uint16_t maxvolt,uint16_t minvolt);
uint8_t AXP17x_SWandVoltCtrl(uint8_t way,uint8_t sw,uint16_t volt);
uint8_t AXP17x_GetBATPercentageBaseCoul(pBatinfo batinfo);

//初始化芯片，返回1初始化失败 返回0初始化成功
uint8_t bsp_InitAXP17x(void)
{
	uint8_t tmp = 0;
	int32_t swp = 0;

	//IIC Init And IRQ brfore
	axp17x_IRQinit();
	axp17x_i2cinit();

	//检查芯片是否存在
	axp17x_delayms(10);
	AXP17x_Read(AXP17x_I2Cx_READADDRESS,AXP17x_BUF0,&tmp,1);
	if(tmp == 0xF0)
	{
		tmp = 0;
		axp17x_delayms(10);
		AXP17x_Read(AXP17x_I2Cx_READADDRESS,AXP17x_BUF1,&tmp,1);
		if(tmp != 0x0F)	return 1;
	}
	else return 1;

	AXP17x_SWandVoltCtrl(DCDC1,ON,DCDC1DEFAULTV);	//此路与主芯片供电，硬件默认自动开启，若运行此句会造成芯片在VBUS接入时关不掉的情况
	AXP17x_SWandVoltCtrl(LDO2,ON,LDO2DEFAULTV);
	AXP17x_SWandVoltCtrl(LDO3,ON,LDO3DEFAULTV);
#ifdef AXP173
	AXP17x_SWandVoltCtrl(DCDC2,ON,DCDC2DEFAULTV);
	AXP17x_SWandVoltCtrl(LDO4,ON,LDO4DEFAULTV);
#endif

	SetShutdownVolt(VOFF3200);//关机电压3.2V  短按唤醒功能关闭
#ifdef AXP173
	tmp = 0x05;	AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,0x10,&tmp,1);//EXTERN 开关打开 DCDC2 打开
	tmp = 0x00;	AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,0x25,&tmp,1);//DCDC2 VRC关 	电压斜率1.6mV/us
#endif
	tmp = 0xe2;	AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,0x30,&tmp,1);//VBUS-IPSOUT通路管理  Vhold限压控制4.4V VBUS限流打开 500mA
//	tmp = 0x06;	AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,0x31,&tmp,1);//关机电压3.2V  短按唤醒功能关闭
	tmp = 0xc1;	AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,0x33,&tmp,1);//充电功能控制打开 目标电压4.2V，充电电流小于10%设置值时结束 ，开机充电电流190mA
	tmp = 0x40;	AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,0x34,&tmp,1);//预充电超时50min 恒流充超时7h
	tmp = 0xff;	AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,0x36,&tmp,1);//开机时间2S 长按键时长 2.5S 按键时长大于关机时长时自动关机，PWROK延迟64ms,关机时长10S
	tmp = 0x57;	AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,0x3A,&tmp,1);//低电压警告1 3350 mv
	tmp = 0x45;	AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,0x3B,&tmp,1);//低电压警告2 3250 mv
	tmp = 0xce;	AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,0x82,&tmp,1);//电池电压电流ADC使能 VBUS电压电流ADC使能  APS电压ADC使能 TS ADC关闭
	tmp = 0x80;	AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,0x83,&tmp,1);//AXP17x  内部温度检测 使能
	tmp = 0x01;	AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,0x8f,&tmp,1);//内部过温不关机
	tmp = 0x80;	AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,0xb8,&tmp,1);//打开库仑计
	tmp = 0x32;	AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,0x84,&tmp,1);//ADC 25HZ 采样

	AXP17x_Read(AXP17x_I2Cx_READADDRESS,AXP17x_BUF2,&tmp,1);
	if(tmp)	batinfo.mark |= 0x80;
	else
	{
		batinfo.mark &= ~0x80;
		tmp = 0xff;
		AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,AXP17x_BUF2,&tmp,1);
	}

	AXP17x_EnableIRQ(AXP17x_NOTIFIER_ON);	//使能用户定义中断
	AXP17x_GetAndClearIRQStatus();			//清除所有中断标志

	/* readInfo(); */
	swp = (AXP17x_GetCoulombChargeCounter() - batinfo.Coulomb);//获得关机时充入的电量
	if(swp < 0)	swp = 0;
	batinfo.batrm += C2mAh(swp);//获得关机时充入的电量

	return 0;
}


uint8_t AXP17x_swandvoltctrl(uint8_t ctrlreg,uint8_t voltreg,uint8_t swbit,
							 uint8_t sw,uint16_t volt,uint16_t maxvolt,uint16_t minvolt)
{
	uint8_t tmp = 0,i = 0;

	AXP17x_Read(AXP17x_I2Cx_READADDRESS,ctrlreg,&tmp,1);
	if((ON == sw) || (IGNORE == sw))
	{
		if(ON == sw)
		{
			tmp |= swbit;
			AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,ctrlreg,&tmp,1);
		}
		tmp = 0;
		AXP17x_Read(AXP17x_I2Cx_READADDRESS,ctrlreg,&tmp,1);
		if(tmp & swbit)
		{
			tmp = 0;
			AXP17x_Read(AXP17x_I2Cx_READADDRESS,voltreg,&tmp,1);
			if(volt < minvolt )	volt = minvolt;
			if(volt > maxvolt )	volt = maxvolt;

			if(swbit == AXP17x_LDO2_SW)
			{
				tmp &= 0x0F;
				tmp |= ((uint8_t)(1.0 * (volt - minvolt)/(maxvolt - minvolt ) * 0x0f)) << 4;
			}
			else if(swbit == AXP17x_LDO3_SW)
			{
				tmp &= 0xF0;
				tmp |= (uint8_t)(1.0 * (volt - minvolt)/(maxvolt - minvolt ) * 0x0f);
			}
#ifdef AXP173
			else if(swbit == AXP17x_DCDC2_SW)
			{
				tmp &= 0x00;
				tmp |= (uint8_t)(1.0 * (volt - minvolt)/(maxvolt - minvolt ) * 0x3F);
			}
#endif
			else
			{
				tmp &= 0x00;
				tmp |= (uint8_t)(1.0 * (volt - minvolt)/(maxvolt - minvolt ) * 0x70);
			}
			AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,voltreg,&tmp,1);
			AXP17x_Read(AXP17x_I2Cx_READADDRESS,voltreg,&i,1);
			if(i == tmp)	return 0;
			else 			return 1;

		}
		else return 1;
	}
	else//OFF
	{
		tmp &= ~swbit;
		AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,ctrlreg,&tmp,1);
		tmp = 0;
		AXP17x_Read(AXP17x_I2Cx_READADDRESS,ctrlreg,&tmp,1);
		if(!(tmp & swbit)) return 0;
		else 				return 1;
	}

//	return 0;
}


/*AXP17x 各路  输出开关控制 及 电压调节
 * 函数名：void AXP17x_SWandVoltCtrl(uint8_t way,uint8_t sw,uint8_t volt)
 * 输入：way		-> DCDC1 DCDC2 LDO2 LDO3 LDO4
 *     sw		-> ON 打开     OFF 关闭  	IGNORE 不进行开关控制，只设置电压  前提是要设置的那一路处于开启状态 否则无效
 * 返回：成功返回0 失败返回 1
 */

uint8_t AXP17x_SWandVoltCtrl(uint8_t way,uint8_t sw,uint16_t volt)
{
	uint8_t tmp = 0;

	switch(way)
	{
#ifdef AXP173
		case DCDC2:
			tmp = AXP17x_swandvoltctrl(AXP17x_SW_CTRL,AXP17x_DCDC2_VOLT_CTRL,AXP17x_DCDC2_SW,
								 	 	sw,volt,AXP17x_DCDC2MAX,AXP17x_DCDC2MIN);
		break;

		case LDO4:
			tmp = AXP17x_swandvoltctrl(AXP17x_SW_CTRL,AXP17x_LDO4_VOLT_CTRL,AXP17x_LDO4_SW,
								 	 	sw,volt,AXP17x_LDO4MAX,AXP17x_LDO4MIN);
		break;
#endif

#if defined (AXP173) || defined (AXP176)
		case DCDC1:
			tmp = AXP17x_swandvoltctrl(AXP17x_SW_CTRL,AXP17x_DCDC1_VOLT_CTRL,AXP17x_DCDC1_SW,
										sw,volt,AXP17x_DCDC1MAX,AXP17x_DCDC1MIN);
		break;

		case LDO2:
			tmp = AXP17x_swandvoltctrl(AXP17x_SW_CTRL,AXP17x_LDO23_VOLT_CTRL,AXP17x_LDO2_SW,
							 	        sw,volt,AXP17x_LDO2MAX,AXP17x_LDO2MIN);
		break;

		case LDO3:
			tmp = AXP17x_swandvoltctrl(AXP17x_SW_CTRL,AXP17x_LDO23_VOLT_CTRL,AXP17x_LDO3_SW,
							 	 	 	 sw,volt,AXP17x_LDO3MAX,AXP17x_LDO3MIN);
		break;
#endif
		default:
			tmp = 1;
		break;
	}

	return tmp;
}


/*AXP17x 获得输入电源状态 充电指示
 * 函数名：uint16_t AXP17x_GetPowerInStatus(void)
 * 输入：
 *
 * 返回：输入电源状态 充电指示   对应 REG 00H 01H 标志位参看头文件
 */
uint16_t AXP17x_GetPowerInStatus(void)
{
	uint16_t tmp = 0;
	AXP17x_Read(AXP17x_I2Cx_READADDRESS,0x00,(uint8_t *)&tmp,2);
	return (tmp);
}

/*AXP17x 关机
 * 函数名：void AXP17x_Shutdown(void)
 * 输入：
 *
 * 返回：
 */
void AXP17x_Shutdown(void)
{
	uint8_t tmp = 0;
	AXP17x_Read(AXP17x_I2Cx_READADDRESS,0x32,&tmp,1);
	tmp |= 0x80;
	AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,0x32,&tmp,1);
}


/*AXP17x 库仑计开关
 * 函数名：void AXP17x_CoulombSW(uint8_t sw)
 * 输入：ON/OFF
 *
 * 返回：
 */
void AXP17x_CoulombSW(uint8_t sw)
{
	uint8_t tmp = 0;
	AXP17x_Read(AXP17x_I2Cx_READADDRESS,AXP17x_COULCTL,&tmp,1);
	if(sw)	tmp |= 0x80;
	else	tmp = 0x00;
	AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,AXP17x_COULCTL,&tmp,1);
}

/*AXP17x 库仑计暂停
 * 函数名：void AXP17x_CoulombPause(uint8_t sw)
 * 输入：
 *
 * 返回：
 */
void AXP17x_CoulombPause(void)
{
	uint8_t tmp = 0;
	AXP17x_Read(AXP17x_I2Cx_READADDRESS,AXP17x_COULCTL,&tmp,1);
	tmp |= 0x40;
	AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,AXP17x_COULCTL,&tmp,1);
}

/*AXP17x 库仑计清除
 * 函数名：void AXP17x_CoulombClear(uint8_t sw)
 * 输入：ON/OFF
 *
 * 返回：
 */
void AXP17x_CoulombClear(void)
{
	uint8_t tmp = 0;
	AXP17x_Read(AXP17x_I2Cx_READADDRESS,AXP17x_COULCTL,&tmp,1);
	tmp |= 0x20;
	AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,AXP17x_COULCTL,&tmp,1);
}


/*AXP17x 库仑计充电计数
 * 函数名：uint32_t AXP17x_GetCoulombChargeCounter(void)
 * 输入：
 *
 * 返回：
 */
uint32_t AXP17x_GetCoulombChargeCounter(void)
{
	uint32_t tmp = 0;
	AXP17x_Read(AXP17x_I2Cx_READADDRESS,0XB0,(uint8_t *)&tmp,4);

	return SWAP32(tmp);
}

/*AXP17x 库仑计放电计数
 * 函数名：uint32_t AXP17x_GetCoulombDisChargeCounter(void)
 * 输入：
 *
 * 返回：
 */
uint32_t AXP17x_GetCoulombDisChargeCounter(void)
{
	uint32_t tmp = 0;
	AXP17x_Read(AXP17x_I2Cx_READADDRESS,0xB4,(uint8_t *)&tmp,4);

	return SWAP32(tmp);
}


/*AXP17x 电池信息监视   每秒调用一次
 * 函数名：void AXP17x_BatinfoMonitor(pBatinfo batinfo)
 * 输入：
 *
 * 返回：电量百分比
 */
void AXP17x_BatinfoMonitor(void *p)
{
	pBatinfo batinfo = NULL;
	uint32_t tmp = 0;
	static uint16_t batrm = 0;
	batinfo = (pBatinfo)p;

	tmp = AXP17x_GetPowerInStatus();//获得充电状态

	//电池首次使用 //当电池首次为设备供电时 该标识置1 设备因电池拔出掉电后 该标识丢失，下次电池再为设备供电时该标识又会置1 来作为首次电量用电压获取的判断
	if((!(batinfo->mark & 0x80)) && (tmp & AXP17x_BATLIVE))
	{
		batinfo->mark |= 0x80;

		//此处需要延时，如果电池插入后AXP 获得的电压还未稳定就会出错
		axp17x_delayms(100);
		batinfo->batsoc = AXP17x_GetBATPercentageBaseVolt();//按电压获得 电量百分比
		batinfo->batrm = (uint16_t)(BATCAP * batinfo->batsoc / 100.0);

		batrm = batinfo->batovc = batinfo->batrm;
		AXP17x_CoulombClear();//清除 库仑计重新计数
	}

	if((tmp & AXP17x_BATLIVE) && (tmp & AXP17x_BATINOROUT) && (tmp & AXP17x_CHARGESTA) && (!(batinfo->mark & 0x01))) //电池已连接电池被充电并正在充电
	{
		if(AXP17x_GetBATPercentageBaseVolt() <= 5) //充电时按电池电压测得电量小于5%时即电压小于一定值  认为电池已被放干
		{
			//置位放干标志
			batinfo->mark |= 0x02;
			batinfo->batrm = 0;		//如果电池电量放的不够干 或造成满充容量越来越小，但如果没有此部会造成电池满充容量越来越大
		}
		else
		{
			batinfo->mark &= 0xfd;
		}
		batinfo->mark |= 0x01;//置位充电标志
		batrm = batinfo->batrm;
		batinfo->batchargetime = 0;//开始充电时 把充电计时清零
		AXP17x_CoulombClear();//清除 库仑计重新计数
	}
	else if((tmp & AXP17x_BATLIVE) && (!(tmp & AXP17x_CHARGESTA)) && (batinfo->mark & 0x01))	//电池存在  曾经在充电 但现在未充电或充电完成
	{
		batinfo->batovc = batrm + C2mAh(AXP17x_GetCoulombChargeCounter());
		batinfo->mark &= 0xfe;
		batinfo->batcdt ++;//充放电次数加1

		if(batinfo->batovc > batinfo->batfcc)	batinfo->batovc = batinfo->batfcc + 10;

		if((!(tmp & AXP17x_VBUSCANUSE)) || (!(tmp & AXP17x_VBUSLIVE)))//充电结束时 VBUS 不可用或不存在 这就是有可能因外部电源不存在引起的充电结束
		{
			batinfo->mark |= 0x04;
		}
		//更新电池满充容量要谨慎 ，暂不进行此操作，可用充电次数来矫正容量
		if(((batinfo->batchargetime > (1800 * 5)) && (!(batinfo->mark & 0x04))) && (batinfo->mark & 0x02)) //充电时电池处于放干状态 并且连续充电时间大于5h 或没有中断过外部电源  且充电前 电池已被放干 则用此次充电后的总电量更新为电池满充容量
		{
			batinfo->batfcc = batinfo->batovc;
			batinfo->mark &= 0xf9;
		}
		//也可以判断 USB 是否存在 配合开始充电时是否是 干充状态 来更新电池 容量

		batinfo->batdischargetime = 0;//充电完成时 把充电计时清零

		AXP17x_CoulombClear();//若出现 关机充电 则 开机读取充电库仑计数值 即为 关机时所充电量

		SetShutdownVolt(VOFF3200);
		//出现软件关机 时也应该清除库伦计

//		return (100);
	}

	if((tmp & AXP17x_CHARGESTA) && (tmp & AXP17x_BATINOROUT)) //电池处于充电状态 且 有电流流入电池
	{
		batinfo->Coulomb = AXP17x_GetCoulombChargeCounter();
		batinfo->batrm = batrm + C2mAh(batinfo->Coulomb);//当前电量 = 充电时剩余的 + 已经充入的
		batinfo->batsoc = (uint8_t)(batinfo->batrm * 100.0/ batinfo->batfcc);//充电时电量%
		batinfo->batcurrent = AXP17x_GetBATChargeCurrent();	// 充电电流
		batinfo->batchargetime ++;

		if(batinfo->batsoc >= 100)	//如果还在充电，并有电流流入电池 即使返回100%，也置为99%
		{
			batinfo->batsoc = 99;
		//	batinfo->batrm = (uint16_t)(0.99 * batinfo->batfcc);
		}
	}
	else if(!(tmp & AXP17x_BATINOROUT)) //电池流出电流
	{
		batinfo->batsoc = AXP17x_GetBATPercentageBaseCoul(batinfo);//放电时电量%
		batinfo->batcurrent = AXP17x_GetBATDisChargeCurrent();	//放电电流
		batinfo->batdischargetime ++;
	}
	if((!(tmp & AXP17x_CHARGESTA)) && (tmp & AXP17x_BATINOROUT))//如果未充电或充电已完成但电池电流方向还是流入在VBUS存在时 则显示充满 ,防止永远显示充不满
	{
		if(AXP17x_GetBATPercentageBaseVolt() >= 100)//按电压获得 电量百分比 纠正电量显示
		{
			batinfo->batsoc = 100;
			batinfo->batovc = batinfo->batrm = batinfo->batfcc;
		}
	}
	if(!(tmp & AXP17x_BATLIVE))//电池拔出 还能运行  说明有外接电源 电量显示为0
	{
		batinfo->mark &= ~0x80;	//清除此位防止先插入USB 后插入电池，这时无论如何电池电量都是99%的问题
		tmp = 0x00;
		AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,AXP17x_BUF2,(uint8_t *)&tmp,1);
		batinfo->batsoc = 0;
//		batinfo->batovc = batinfo->batrm;
//		batinfo->batrm = 0;
	}

//	batinfo->batrdc = AXP17x_CalcAXPInternalRDC();			//内阻   需要关掉设备一般不获取
	batinfo->batvolt = AXP17x_GetBATVolt();					//电池电压
	batinfo->battemp = AXP17x_GetAXPInternalTemp();			//用芯片内部温度代替电池温度

	//电量的指示，充电中亮红灯，充电完成亮绿灯拔掉USB后绿灯灭，电量过低红灯闪烁，正常运行指示灯,在leddemo()

//	return (batinfo->batsoc);
}

/*AXP17x 得到电池电量百分比 基于库仑计 计算的 mAh
 * 函数名：uint8_t AXP17x_GetBATPercentageBaseCoul(void)
 * 输入：
 *
 * 返回：电量百分比 0~100
 */
uint8_t AXP17x_GetBATPercentageBaseCoul(pBatinfo batinfo)
{
	batinfo->batrm = batinfo->batovc - C2mAh(AXP17x_GetCoulombDisChargeCounter());//剩余的电量 = 充电完成时电量 - 放掉的电量

	batinfo->batsoc = (uint8_t)(batinfo->batrm * 100.0/ batinfo->batfcc);

	if(batinfo->batsoc > 100)
	{
		//容量值存在问题
		//矫正 电池容量BatCap 或    库仑计
		batinfo->batsoc = 100;
	}
	else if(batinfo->batsoc <= 0)
	{
		//剩余电量为0 时若未关机则显示 1%
		batinfo->batsoc = 1;
		batinfo->batrm = 1;//batinfo->batfcc / 100;
	}

	//加入与电压的对比 来纠错

	return ((uint8_t)(batinfo->batsoc));
}

/*AXP17x 得到电池电量百分比 基于电压测量
 * 函数名：uint8_t AXP17x_GetBATPercentageBaseVolt(void)
 * 输入：
 *
 * 返回：电量百分比 0~100
 */
uint8_t AXP17x_GetBATPercentageBaseVolt(void)
{
	uint16_t ocv = 0;//开路电压 mV
	uint16_t ccv = 0;//闭路电压   mV
	uint16_t cci = 0;//闭路电流   mA
	uint16_t rdc = 0;//电池内阻  mΩ

	if(AXP17x_GetPowerInStatus() & AXP17x_BATLIVE)//电池存在
	{
		ccv = AXP17x_GetBATVolt();
		cci = AXP17x_GetBATDisChargeCurrent();
		rdc = AXP17x_CalcAXPInternalRDC();

		if(rdc < 50)	rdc = BATRDC;

		ocv = (uint16_t)(ccv + (rdc * cci)/1000.0);

		if(ocv >= 4150)			return 100;
		else if(ocv >= 4080)	return 90;
		else if(ocv >= 4000)	return 80;
		else if(ocv >= 3930)	return 70;
		else if(ocv >= 3870)	return 60;
		else if(ocv >= 3820)	return 50;
		else if(ocv >= 3790)	return 40;
		else if(ocv >= 3770)	return 30;
		else if(ocv >= 3730)	return 20;
		else if(ocv >= 3700)	return 15;
		else if(ocv >= 3680)	return 10;
		else if(ocv >= 3500)	return  5;
		else if(ocv >= 3210)	return  1;
		else					return  0;
	}
	else return (100);
}


/*AXP17x 得到VBUS 电压
 * 函数名：uint16_t AXP17x_GetVBUSVolt(void)
 * 输入：
 *
 * 返回：mV
 */
uint16_t AXP17x_GetVBUSVolt(void)
{
	uint16_t tmp = 0;
	AXP17x_Read(AXP17x_I2Cx_READADDRESS,0x5A,(uint8_t *)&tmp,2);
	tmp = ((tmp & 0x0f00) >> 8) | ((tmp & 0x00ff) << 4);
	tmp = (uint16_t)(1.7 * tmp);
	return (tmp);
}

/*AXP17x 得到VBUS 电流
 * 函数名：uint16_t AXP17x_GetVBUSCurrent(void)
 * 输入：
 *
 * 返回：mA
 */
uint16_t AXP17x_GetVBUSCurrent(void)
{
	uint16_t tmp = 0;
	AXP17x_Read(AXP17x_I2Cx_READADDRESS,0x5C,(uint8_t *)&tmp,2);
	tmp = ((tmp & 0x0f00) >> 8) | ((tmp & 0x00ff) << 4);
	tmp = (uint16_t)(0.375 * tmp);
	return (tmp);
}


/*AXP17x 得到电池 电压
 * 函数名：uint16_t AXP17x_GetBATVolt(void)
 * 输入：
 *
 * 返回：mV
 */
uint16_t AXP17x_GetBATVolt(void)
{
	uint16_t tmp = 0;
	AXP17x_Read(AXP17x_I2Cx_READADDRESS,0x78,(uint8_t *)&tmp,2);
	tmp = ((tmp & 0x0f00) >> 8) | ((tmp & 0x00ff) << 4);
	tmp = (uint16_t)(1.1 * tmp);
	return (tmp);
}

/*AXP17x 得到电池充电 电流
 * 函数名：uint16_t AXP17x_GetBATChargeCurrent(void)
 * 输入：
 *
 * 返回：mA
 */
uint16_t AXP17x_GetBATChargeCurrent(void)
{
	uint16_t tmp = 0;
	AXP17x_Read(AXP17x_I2Cx_READADDRESS,0x7A,(uint8_t *)&tmp,2);
	tmp = ((tmp & 0x1f00) >> 8) | ((tmp & 0x00ff) << 5);
	tmp = (uint16_t)(0.5 * tmp);
	return (tmp);
}

/*AXP17x 得到电池放电 电流
 * 函数名：uint16_t AXP17x_GetBATDisChargeCurrent(void)
 * 输入：
 *
 * 返回：mA
 */
uint16_t AXP17x_GetBATDisChargeCurrent(void)
{
	uint16_t tmp = 0;
	AXP17x_Read(AXP17x_I2Cx_READADDRESS,0x7C,(uint8_t *)&tmp,2);
	tmp = ((tmp & 0x1f00) >> 8) | ((tmp & 0x00ff) << 5);
	tmp = (uint16_t)(0.5 * tmp);
	return (tmp);
}

/*AXP17x 得到APS 电压
 * 函数名：uint16_t AXP17x_GetAPSVolt(void)
 * 输入：
 *
 * 返回：mV
 */
uint16_t AXP17x_GetAPSVolt(void)
{
	uint16_t tmp = 0;
	AXP17x_Read(AXP17x_I2Cx_READADDRESS,0x7E,(uint8_t *)&tmp,2);
	tmp = ((tmp & 0x0f00) >> 8) | ((tmp & 0x00ff) << 4);
	tmp = (uint16_t)(1.4 * tmp);
	return (tmp);
}

/*AXP17x 得到AXP 内部温度
 * 函数名：uint16_t AXP17x_GetAXPInternalTemp(void)
 * 输入：
 *
 * 返回：0.1℃     -144.7~264.8 ℃
 */
int16_t AXP17x_GetAXPInternalTemp(void)
{
	int16_t tmp = 0;
	AXP17x_Read(AXP17x_I2Cx_READADDRESS,0x5E,(uint8_t *)&tmp,2);
	tmp = ((tmp & 0x0f00) >> 8) | ((tmp & 0x00ff) << 4);
	tmp = (int16_t)(0.1 * tmp);
	return (tmp);
}


/*AXP17x 得到AXP 内阻
 * 函数名：uint16_t AXP17x_CalcAXPInternalRDC(void)
 * 输入：	CloseAllDevice();关闭所有设备 及其电源输出 注意AXP  IIC不能掉电,
 * 		OpenAllDevice();打开所有设备及其电源
 *
 * 返回：内阻  = (电池开路电压 - 电池带载电压) / 电池带载电流     mΩ  返回0 电池不存在
 *
 * 注意：测算内阻时会关闭各路输出只保留单片机和AXP工作，其他能关断的要关断或者进入睡眠模式
 *
 */
uint16_t AXP17x_CalcAXPInternalRDC(void)
{
	uint16_t rdc = 0;//内阻
	uint16_t ocv = 0;//开路电压
	uint16_t ccv = 0;//闭路电压
	uint16_t cci = 0;//闭路电流

	if(AXP17x_GetPowerInStatus() & AXP17x_BATLIVE)//电池存在
	{
		//关闭所有不必要的输出
		//CloseAll
		//关设备
		//关电源

	//	AXP17x_SWandVoltCtrl(DCDC1,OFF,DCDC1DEFAULTV);
	//	AXP17x_SWandVoltCtrl(LDO2,OFF,LDO2DEFAULTV);
	//	AXP17x_SWandVoltCtrl(LDO3,OFF,LDO3DEFAULTV);
//#ifdef AXP173
	//	AXP17x_SWandVoltCtrl(DCDC2,OFF,DCDC2DEFAULTV);
	//	AXP17x_SWandVoltCtrl(LDO4,OFF,LDO4DEFAULTV);
//#endif

		CloseAllDevice();

		axp17x_delayms(100);
		ocv = AXP17x_GetBATVolt();

		//打开需要的输出进入正常工作模式
		//OpenAll

		//开电源

	//	AXP17x_SWandVoltCtrl(DCDC1,ON,DCDC1DEFAULTV);
	//	AXP17x_SWandVoltCtrl(LDO2,ON,LDO2DEFAULTV);
	//	AXP17x_SWandVoltCtrl(LDO3,ON,LDO3DEFAULTV);
//#ifdef AXP173
	//	AXP17x_SWandVoltCtrl(DCDC2,ON,DCDC2DEFAULTV);
	//	AXP17x_SWandVoltCtrl(LDO4,ON,LDO4DEFAULTV);
//#endif

		//开设备

		OpenAllDevice();

		axp17x_delayms(100);
		ccv = AXP17x_GetBATVolt();
		axp17x_delayms(10);
		cci = AXP17x_GetBATDisChargeCurrent();
		axp17x_delayms(10);

		rdc = (uint16_t)(((ocv - ccv) * 1000.0)/ cci);

		return (rdc);
	}
	else	return (0);
}

/*AXP17x 使能用户定义中断 AXP17x_NOTIFIER_ON
 * 函数名：void SetShutdownVolt(uint16_t volt)
 * 输入：volt 0~7 ->  2600~3300 step = 100
 *
 * 返回：写入成功返回0 否则返回实际写入值
 */
void SetShutdownVolt(uint8_t volt)
{
	uint8_t tmp = 0;
	volt &= 0x07;
	AXP17x_Read(AXP17x_I2Cx_READADDRESS,0x31,&tmp,1);
	tmp &= ~0x07;
	if(AXP17x_GetBATVolt() < (2600 + volt * 100))	//电池当前电压低于 要设定的电压
		tmp |= VOFF3000;//设为最低电压
	else
		tmp |= volt;
	AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,0x31,&tmp,1);//关机电压3.2V  短按唤醒功能关闭

}

/*AXP17x 使能用户定义中断 AXP17x_NOTIFIER_ON
 * 函数名：uint32_t AXP17x_EnableIRQ(uint32_t tmp)
 * 输入：REG44~47 = tmp
 *
 * 返回：写入成功返回0 否则返回实际写入值
 */

uint32_t AXP17x_EnableIRQ(uint32_t tmp)
{
	uint32_t t = 0;
	AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,AXP17x_IRQCTL_REG1,(uint8_t *)&tmp,4);
	AXP17x_Read(AXP17x_I2Cx_READADDRESS,AXP17x_IRQCTL_REG1,(uint8_t *)&t,4);

	if(t == tmp)	return 0;
	else			return t;
}

/*AXP17x 得到中断状态并清除中断寄存器
 * 函数名：uint32_t AXP17x_GetAndClearIRQStatus(void)
 * 输入：
 *
 * 返回：返回 中断寄存器状态
 *     bit 0~7 		reg 0x44
 *     bit 8~15 	reg 0x45
 *     bit 16~23 	reg 0x46
 *     bit 24~31 	reg 0x47
 */

uint32_t AXP17x_GetAndClearIRQStatus(void)
{
	uint32_t tmp = 0;

	AXP17x_Read(AXP17x_I2Cx_READADDRESS,AXP17x_IRQSTA_REG1,(uint8_t *)&tmp,4);
	AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,AXP17x_IRQSTA_REG1,(uint8_t *)&tmp,4);

	return tmp;
}

/*AXP17x 得到中断状态
 * 函数名：uint32_t AXP17x_GetIRQStatus(void)
 * 输入：
 *
 * 返回：返回 中断寄存器状态
 *     bit 0~7 		reg 0x44
 *     bit 8~15 	reg 0x45
 *     bit 16~23 	reg 0x46
 *     bit 24~31 	reg 0x47
 */

uint32_t AXP17x_GetIRQStatus(void)
{
	uint32_t tmp = 0;

	AXP17x_Read(AXP17x_I2Cx_READADDRESS,AXP17x_IRQSTA_REG1,(uint8_t *)&tmp,4);

	return tmp;
}

/*AXP17x 清除中断状态
 * 函数名：uint32_t AXP17x_ClearIRQStatus(void)
 * 输入： 要清除的中断状态 位 可以多位 或
 *
 * 返回：成功返回 0 失败返回 中断寄存器状态
 */

uint32_t AXP17x_ClearIRQStatus(uint32_t tmp)
{
	uint32_t t = 0;
	AXP17x_Write(AXP17x_I2Cx_WRITEADDRESS,AXP17x_IRQSTA_REG1,(uint8_t *)&tmp,4);

	AXP17x_Read(AXP17x_I2Cx_READADDRESS,AXP17x_IRQSTA_REG1,(uint8_t *)&t,4);
	if(! (t & tmp)) 	return 0;
	else 				return t;
}

/* AXP各状态回调函数集合
 * 输入：
 */
__weak void UsbInCallBack(void)
{
	((void)(NULL));
}
__weak void UsbOutCallBack(void)
{
	((void)(NULL));
}
__weak void BatteryInCallBack(void)
{
	((void)(NULL));
}
__weak void BatteryOutCallBack(void)
{
	((void)(NULL));
}
__weak void keyShortPressCallback(void)
{
	((void)(NULL));
}
__weak void keyLongPressCallback(void)
{
	((void)(NULL));
}
__weak void PoweringCallBack(void)
{
	((void)(NULL));
}
__weak void PoweredCallBack(void)
{
	((void)(NULL));
}
__weak void DCDC1LowCallBack(void)
{
	((void)(NULL));
}
__weak void LowPowerCallBack(void)
{
	((void)(NULL));
}

/*AXP 中断回掉函数（可按照如下例子重定义本函数）
 * 函数名void AXP17x_IRQCallBack(uint32_t *pam)
 * 输入：
 *
 * 返回：返回 中断寄存器状态
 */
void AXP17x_IRQCallBack(uint32_t *pam)
{
	*pam = AXP17x_GetIRQStatus();//获得中断状态 */

	if(*pam & AXP17x_IRQ_USBIN)//USB 插入 */
	{
		UsbInCallBack();
//		dbgprintf(2,"USB 插入 \r\n");
	}
	if(*pam & AXP17x_IRQ_USBRE)//USB 拔出 */
	{
		UsbOutCallBack();
//		dbgprintf(2,"USB 拔出 \r\n");
	}
	if(*pam & AXP17x_IRQ_BATIN)//电池 插入 */
	{
		BatteryInCallBack();
//		dbgprintf(2,"电池 插入 \r\n");
	}
	if(*pam & AXP17x_IRQ_BATRE)//电池 拔出 */
	{
		BatteryOutCallBack();
//		dbgprintf(2,"电池 拔出 \r\n");
	}
	if(*pam & AXP17x_IRQ_PEKLO)//按键短按 */
	{
		keyShortPressCallback();
//		dbgprintf(2,"按键短按 \r\n");
	}
	if(*pam & AXP17x_IRQ_PEKSH)//按键长按 */
	{
		keyLongPressCallback();
//		dbgprintf(2,"按键长按 \r\n");
	}
	if(*pam & AXP17x_IRQ_CHAST)//正在充电 */
	{
		PoweringCallBack();
//		dbgprintf(2,"正在充电 \r\n");
		//保存  充电库伦计数与放电库伦计数之差 */
		//保存以上3 值 */
	}
	if(*pam & AXP17x_IRQ_CHAOV)//充电完成 */
	{
		PoweredCallBack();
//		dbgprintf(2,"充电完成\r\n");
		//获得本次充电 库仑计数值 */
		//本次充电库仑计数值 + 开始充电时   充电库伦计数与放电库伦计数之差 = 当前 可用电荷量	可以此值更新电池容量(3.2V ~ 4.2V 电池可用区间的 容量) */
		//电量置为100% */
	}
	if(*pam & AXP17x_IRQ_DCDC1LO)//DCDC1 电压过低 */
	{
		DCDC1LowCallBack();
//		dbgprintf(2,"DCDC1 电压过低 \r\n");
	}
	if(*pam & AXP17x_IRQ_EXTLOWARN)//电池 电压过低 */
	{
		LowPowerCallBack();
//		dbgprintf(2,"电池 电压过低 \r\n");
		//将电池剩余电量更改为 1% 并修改百分比	!!! */
		//保存 电池电量信息 */
	}
#ifdef AXP173
	if(*pam & AXP17x_IRQ_ACIN)//AC 插入 */
	{
//		dbgprintf(2,"AC 插入 \r\n");
	}
	if(*pam & AXP17x_IRQ_ACRE)//AC 拔出 */
	{
//		dbgprintf(2,"AC 拔出 \r\n");
	}
	if(*pam & AXP17x_IRQ_DCDC2LO)//DCDC2 低压 */
	{
//		dbgprintf(2,"DCDC2 低压 \r\n");
	}
	if(*pam & AXP17x_IRQ_LDO4LO)//LDO4 低压 */
	{
//		dbgprintf(2,"LDO4 低压 \r\n");
	}
#endif

	AXP17x_GetAndClearIRQStatus();	//清除所有中断状态 */
}

//AXP17X 中断（需将本函数放置在gpio外部中断或者使用rtos向对应任务发送信号）
void AXP17x_IRQ(void *p)
{
	batinfo.mark |= 0x08;
	if(batinfo.mark & 0x08)//电源芯片发生中断
	{
		batinfo.mark &= ~0x08;
		AXP17x_IRQCallBack(&batinfo.irq);
//		dbgprintf(2,"中断状态			0x%08X\r\n",(unsigned int)batinfo.irq);
	}
}





